/************************************************************************************
**  
* @copyright (c) 2015-, Technology Co., LTD. All Right Reserved.
*
*************************************************************************************/
/**
* @file     duye_cap_linklayer_service.cpp
* @version     
* @brief      
* @author   
* @date     2013-01-08
* @note 
*
*  1. 2018-01-08 created this file
* 
*/
#include <duye_logger.h>
#include <duye_cap_linklayer_service.h>
#include <duye_cap_packet.h>
#include <duye_cap.h>
#include <duye_cap_filter_engine.h>

namespace duye {

static const int8* DUYE_LOG_PREFIX = "duye.cap.linklayer.service";
static const uint32 MAX_CAPTURE_COUNT = 10;

LinkLayerService::LinkLayerService() : CapDataService("LinkLayerService") {}
LinkLayerService::~LinkLayerService() {
	for (LinkLayerListenerMap::iterator iter = m_listenerMap.begin(); iter != m_listenerMap.end(); ++iter) {
		delete iter->second;
	}
	m_listenerMap.clear();

	if (!m_capFile.empty()) {
		Pcap::instance().closeReadFile();	
	} else {
		Pcap::instance().closeDevice();
	}
}

bool LinkLayerService::start() {
	if (m_netcard.empty() && m_capFile.empty()) {
		DUYE_ERROR("don't setting interface or cap file");
		return false;
	}

	if (!m_capFile.empty()) {
		if (!Pcap::instance().openReadFile(m_capFile)) {
			return false;
		}
	} else {
		if (!Pcap::instance().openDevice(m_netcard, 0)) {
			return false;
		}
	}

	startTask();

	return true;
}

bool LinkLayerService::stop() {
	return true;
}

bool LinkLayerService::run() {
	DUYE_INFO("LinkLayerService Start");

	while (true) {
		Pcap::instance().dispatchPacket(MAX_CAPTURE_COUNT, LinkLayerService::pcapCallback, this);
	}

	DUYE_INFO("LinkLayerService Exit");

	return true;
}

bool LinkLayerService::addListener(DataServiceListener* listener, const FilterRule* filterRule) {
	LinkLayerListener* linkListener = dynamic_cast<LinkLayerListener*>(listener);
	if (linkListener == NULL) {
		return false;
	}
	
	FilterRule* copyFilterRule = NULL;
	if (filterRule == NULL) {
		m_listenerMap.insert(std::make_pair(linkListener, copyFilterRule));
	} else {
		copyFilterRule = new FilterRule(*filterRule);
		m_listenerMap.insert(std::make_pair(linkListener, copyFilterRule));
	}
	
	return true;
}

bool LinkLayerService::delListener(DataServiceListener* listener) {
	m_listenerMap.erase(dynamic_cast<LinkLayerListener*>(listener));
	return true;
}

void LinkLayerService::setNetcard(const std::string& netcard) {
	m_netcard = netcard;
}

void LinkLayerService::setCapfile(const std::string& capfile) {
	m_capFile = capfile;
}

void LinkLayerService::packetHandle(const PcapPkthdr* pcapPktHeader, const uint8* pkt) {
	DUYE_DEBUG("Capture a packet: caplen = %d", pcapPktHeader->caplen);
	DUYE_DEBUG("Capture a packet: len = %d", pcapPktHeader->len);

	PacketReference pktRef(new Packet());
	pktRef->setPcapPkthdr(*pcapPktHeader);
	pktRef->setPktTime(pcapPktHeader->ts.tv_sec * 1000000LL + pcapPktHeader->ts.tv_usec);
	pktRef->setRawData(const_cast<uint8*>(pkt));
	pktRef->setRawDataLen(pcapPktHeader->caplen); 
	if (!pktRef->parserPkt(const_cast<uint8*>(pkt), pcapPktHeader->caplen)) {
		return;
	}

	DUYE_DEBUG("Protocol type(%d) is %s.\n", 
		pktRef->getLinkLayerProto(), 
		Protocols::instance().getName(pktRef->getLinkLayerProto()).c_str());

	// dispense packet
	for (LinkLayerListenerMap::iterator iter = m_listenerMap.begin(); iter != m_listenerMap.end(); ++iter) {
		if (FilterEngine::instance().filterPkt(pktRef, iter->second)) {
			iter->first->onLinkLayerPacket(pktRef);
		}
	}
}

void LinkLayerService::pcapCallback(void* user, const PcapPkthdr* pcapPktHeader, const uint8* pkt) {
	if (user == NULL) {
		return;
	}

	LinkLayerService* linklayerService = reinterpret_cast<LinkLayerService*>(user);
	if (linklayerService == NULL) {
		DUYE_ERROR("reinterpret_cast<LinkLayerService*>(user) failed");
		return;
	}

	linklayerService->packetHandle(pcapPktHeader, pkt);
}

}
